package com.flyduck.common.config;

import com.flyduck.modules.system.domain.SysMenu;
import com.flyduck.modules.system.domain.SysRole;
import com.flyduck.modules.system.domain.SysUser;
import com.flyduck.modules.system.service.SysMenuService;
import com.flyduck.modules.system.service.SysRoleService;
import com.flyduck.modules.system.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: flyduck-admin
 * @description:
 * @author: flyduck
 * @create: 2020-05-09 20:28
 **/
@Slf4j
public class UserRealm extends AuthorizingRealm {

    @Lazy
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    @Lazy
    private SysRoleService sysRoleService;
    @Autowired
    @Lazy
    private SysMenuService sysMenuService;

    /**
     * 认证(这个方法的调用者如果发现这个方法返回空,就会返回没有未知用户的错误，如果不为空，就会拿到token的密码和你返回的用户信息的密码比对
     * 因此这个方法要么返回空，要么不为空
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        log.info("shiro认证token：{}",token);
        //获取身份信息
        String username = (String) token.getPrincipal();
        //根据用户名从数据库查用户信息
        SysUser sysUser = sysUserService.findUserByUsername(username);
        if(sysUser == null){
            return null;
        }
        //认证
        //参数：主体，正确的密码，盐，当前的realm名称  这里会把sysUser放入shiro管理的session中，在任何地方可以拿到这个sysUser
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                sysUser,
                sysUser.getPassword(),
                ByteSource.Util.bytes(sysUser.getUsername()),
                this.getName());
        return info;
    }

    /**
     * 授权
     * web doGetAuthorizationInfo什么时候调用
     * 1.方法上面有注解
     * 2.页面上面有授权标签
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("shiro授权");
        //获取用户的身份信息
        SysUser sysUser = (SysUser) principalCollection.getPrimaryPrincipal();

        //根据用户查询角色和权限
        List<String> roleCodes = new ArrayList<>();
        List<String> permissions = new ArrayList<>();


        if(sysUser.getAdmin()){
            //=====是否为管理员
            permissions.add("*:*");
        }else {
            //=====不是管理员:查询角色和权限
            List<SysRole> roles = sysRoleService.getRolesByUserId(sysUser.getId());
            roleCodes = roles.stream().map(SysRole::getCode).collect(Collectors.toList());
            List<SysMenu> menus = sysMenuService.getMenusByUserId(sysUser.getId());
            permissions = menus.stream().map(SysMenu::getPermission).filter(x -> StringUtils.hasText(x)).collect(Collectors.toList());
        }

        //给授权信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roleCodes);
        info.addStringPermissions(permissions);

        return info;
    }


}
